import React from 'react';
import classNames from 'classnames';

import { IControledDOMProps } from '../../utils/props';

import { Icon } from '../icon';
import { Dropdown } from '../dropdown';
import { Spinner } from '../spinner';

export interface ICascaderOption {
  name: string;
  id: number | string;
  children?: ICascaderOption[];
}

export interface ICascaderProps extends IControledDOMProps {
  className?: string;
  style?: React.CSSProperties;
  options: ICascaderOption[];
  value?: ICascaderOption[];
  defaultValue?: ICascaderOption[];
  tabTitle?: string[];
  onChange?: ((value: ICascaderOption[] | []) => void);
  loadData?: (value: ICascaderOption) => Promise<ICascaderOption>; // 加载数据的方法
  placeholder?: string;
}

export interface ICascaderState {
  open: boolean;
  showOptions: ICascaderOption[];
  selectedMenu: ICascaderOption[];
  currentDeepLevel: number;
  loading: boolean;
}

export class Cascader extends React.Component<ICascaderProps, ICascaderState> {
  public static defaultProps = {
    className: '',
    tabTitle: ['省份', '城市', '县区', '街道'],
    placeholder: '请选择收货地址',
    style: {},
  };

  public selectedMenuOptions: ICascaderOption[][];
  public canCloseMenu: boolean;
  public closeInitTimer: number | null;

  constructor(props: ICascaderProps) {
    super(props);
    this.state = {
      open: false,                        /*** 下拉菜单是否显示 */
      showOptions: [],                    /***当前显示菜单列表 */
      selectedMenu: [],                   /***已选菜单列表 */
      currentDeepLevel: 0,                /***当前菜单层级 */
      loading: false,                     /***数据异步加载时是否显示loading */
    };
    this.selectedMenuOptions = [];        /***已选的菜单 */
    this.canCloseMenu = false;            /***是否可以关闭下拉菜单 */
    this.closeInitTimer = null;           /***关闭菜单后默认地址设置定时器 */
    this.onChange = this.onChange.bind(this);
    this.loadData = this.loadData.bind(this);
    this.renderMenuOptions = this.renderMenuOptions.bind(this);
    this.renderMenuTab = this.renderMenuTab.bind(this);
    this.inputClick = this.inputClick.bind(this);
    this.handleMenu = this.handleMenu.bind(this);
    this.updateCurrentMenu = this.updateCurrentMenu.bind(this);
    this.updateCurrentShowOptions = this.updateCurrentShowOptions.bind(this);
    this.initData = this.initData.bind(this);
    this.deepOptions = this.deepOptions.bind(this);
    this.clickCascader = this.clickCascader.bind(this);
    this.clickDocument = this.clickDocument.bind(this);
  }

  /**
   * 点击菜单项
   * @param menu
   */
  public handleMenu(menu: ICascaderOption) {
    const { tabTitle = [] } = this.props;
    const { currentDeepLevel, selectedMenu } = this.state;
    const { children = [] } = menu;
    const curSelectMenuIndex = selectedMenu.findIndex((v) => v.id === menu.id);
    /*** 重复选到之前选过的菜单 ***/
    if (curSelectMenuIndex >= 0 && currentDeepLevel < tabTitle.length - 1) {
      this.updateCurrentShowOptions(currentDeepLevel + 1);
      return;
    }
    /*** 最后一层重新选择 **/
    if (tabTitle.length === currentDeepLevel) {
      this.setState({
        open: false,
        selectedMenu: selectedMenu.slice(0, currentDeepLevel - 1).concat(menu),
      });
      this.updateDeepLevel(currentDeepLevel + 1);
    } else {
      /*** 非重新选择首次点击 **/
      if (selectedMenu.length === currentDeepLevel) {
        this.setState({
          selectedMenu: selectedMenu.slice(0, currentDeepLevel).concat(menu),
        }, () => {
          this.onChange();
          if (!!children.length || currentDeepLevel < tabTitle.length - 1) {
            if (!children.length) {
              this.loadData();
            } else {
              this.selectedMenuOptions = this.selectedMenuOptions.slice(0, currentDeepLevel + 1);
              this.selectedMenuOptions.push(children);
            }
            this.updateCurrentMenu(children);
            this.updateDeepLevel(currentDeepLevel + 1);
          } else if (currentDeepLevel === tabTitle.length - 1) {
            this.setState({
              open: false,
            });
            this.selectedMenuOptions = this.selectedMenuOptions.slice(0, currentDeepLevel + 1);
            this.selectedMenuOptions.push(children);
            this.updateDeepLevel(currentDeepLevel + 1);
          }
        });
      } else {
        /*** 重新选择首次重选 **/
        if (currentDeepLevel < tabTitle.length) {
          if (currentDeepLevel === tabTitle.length - 1) {
            this.setState({
              open: false,
              selectedMenu: selectedMenu.slice(0, currentDeepLevel).concat(menu),
            }, () => {
              this.onChange();
            });
          } else {
            this.setState({
              selectedMenu: selectedMenu.slice(0, currentDeepLevel).concat(menu),
            }, () => {
              this.onChange();
              this.updateDeepLevel(currentDeepLevel + 1);
              if (!children.length) {
                this.loadData();
              } else {
                this.selectedMenuOptions = this.selectedMenuOptions.slice(0, currentDeepLevel + 1);
                this.selectedMenuOptions.push(children);
                this.updateCurrentMenu(children);
              }
            });
          }
        }
      }
    }
  }

  /**
   * 选择完成后的回调所选内容
   */
  public onChange() {
    const { onChange } = this.props;
    const { selectedMenu } = this.state;
    if (onChange) {
      onChange(selectedMenu);
    }
  }

  /**
   * 异步加载菜单
   */
  public loadData() {
    const { loadData } = this.props;
    const { selectedMenu, currentDeepLevel } = this.state;
    const that = this;
    if (loadData) {
      let lastSelectMenu = selectedMenu[selectedMenu.length - 1] || {};
      if (lastSelectMenu.id) {
        this.setState({
          loading: true,
        });
        loadData(lastSelectMenu).then((menu: ICascaderOption) => {
          if (menu.children) {
            this.selectedMenuOptions = this.selectedMenuOptions.slice(0, currentDeepLevel + 1);
            this.selectedMenuOptions.push(menu.children);
            that.setState({
              showOptions: menu.children || [],
              loading: false,
            });
          }
        });
      }
    } else {
      this.selectedMenuOptions = this.selectedMenuOptions.slice(0, this.state.currentDeepLevel + 1);
      this.selectedMenuOptions.push([]);
      this.updateCurrentMenu([]);
      this.onChange();
    }
  }

  /**
   * 更新当前菜单内容列表
   * @param menu: 要被设置的菜单
   */
  public updateCurrentMenu(menu: ICascaderOption[]) {
    this.setState({
      showOptions: menu,
    });
  }

  /**
   * 更新当前已选的面板
   * @param level:被选的层级索引
   */
  public updateCurrentShowOptions(level: number) {
    if (this.selectedMenuOptions[level]) {
      this.updateCurrentMenu(this.selectedMenuOptions[level]);
      this.updateDeepLevel(level);
    }
  }

  /**
   * 更新已选菜
   */
  public updateDeepLevel(level: number, callback?: () => void): void {
    const { tabTitle = [] } = this.props;
    this.setState({
      currentDeepLevel: Math.min(level, tabTitle.length),
    }, callback);
  }

  /**
   * 下拉展开选项
   */
  public inputClick(): void {
    this.setState({
      open: true,
    });
    this.canCloseMenu = true;
  }

  /**
   * 点击级联选择区域
   */
  public clickCascader(): void {
    this.canCloseMenu = false;
  }

  /**
   * 点击 document 判断是否在cascader中，判断是否关闭下拉菜单
   */
  public clickDocument(): void {
    const { open } = this.state;
    /***打开菜单状态 */
    if (open) {
      /***判断是否点在组件部分 */
      if (this.canCloseMenu) {
        const { selectedMenuOptions } = this;
        const realMenuLen = selectedMenuOptions.length;
        const lastMenuOption = selectedMenuOptions[realMenuLen - 1];
        const showLevel = lastMenuOption && lastMenuOption.length ? realMenuLen - 1 : realMenuLen - 2;
        this.setState({
          open: false,
        });
        if (this.closeInitTimer) {
          window.clearTimeout(this.closeInitTimer);
          this.closeInitTimer = null;
        }
        this.closeInitTimer = window.setTimeout(() => {
          this.setState({
            currentDeepLevel: showLevel,
            showOptions: selectedMenuOptions[showLevel],
          });
        }, 300);
      } else {
        this.canCloseMenu = true;
      }
    }
  }

  /***
   * 递归初始化当前菜单、当前层级、已选菜单等
   * @param currentOptions: 递归时的当前options
   */
  public async deepOptions(currentOptions: ICascaderOption[]) {
    const { defaultValue = [] } = this.props;
    const {currentDeepLevel} = this.state;
    if (this.state.currentDeepLevel < defaultValue.length) {
      const menu = currentOptions.filter((v) => v.id === defaultValue[currentDeepLevel].id)[0];
      if (menu) {
         await this.handleMenu(menu);
      }
      if (!!this.state.showOptions.length) {
        this.deepOptions(this.state.showOptions);
      }
    }
  }

  /**
   * 初始化当前菜单
   * @param props: 即this.props
   */
  public initData(props: ICascaderProps = this.props) {
    const { options } = props;
    if (options.length) {
      this.selectedMenuOptions.push(options);
    }
    this.setState({
      showOptions: options,
    }, () => {
      this.deepOptions(options);
    });
  }

  /**
   * 渲染被选择的菜单tab栏
   */
  public renderMenuTab() {
    const { tabTitle = [] } = this.props;
    const { currentDeepLevel, selectedMenu } = this.state;
    return (
      <header className="br-cascader__tabs">
        {
          tabTitle.map((item, i) => {
            const lastItemActive = tabTitle.length === currentDeepLevel && (currentDeepLevel === i + 1);
            const active = currentDeepLevel === i || lastItemActive;
            const cantClickItem = i > selectedMenu.length;
            return (
              <span key={i}
                className={classNames('br-cascader__tab',
                  { 'br-cascader__tab-active': active },
                  { 'br-cascader__tab-cantClick': cantClickItem })}
                onClick={() => (!cantClickItem ? this.updateCurrentShowOptions(i) : {})}>
                {item}
              </span>
            );
          })
        }
      </header>
    );
  }

  /**
   * 渲染当前菜单选项
   */
  public renderMenuOptions() {
    const { showOptions, currentDeepLevel, selectedMenu, loading } = this.state;
    const { tabTitle = [] } = this.props;
    const currentMenu = selectedMenu[Math.min(currentDeepLevel, tabTitle.length - 1)] || {};
    if (loading) {
      return (
        <div className="br-cascader__options-loading">
          <Spinner className="br-cascader__menu-loading-icon" />
        </div>
      );
    }
    if (!showOptions.length) {
      return (
        <div className="br-cascader__options-empty">
          <Icon className="br-cascader__options-empty-icon" type="location-empty" size={50} />
          <p className="br-cascader__options-empty-text">{tabTitle[currentDeepLevel]}为空</p>
        </div>
      );
    }
    return (
      <div className="br-cascader__options">
        {
          showOptions.map((item) => {
            return (
              <span className={`br-cascader__option ${currentMenu.id === item.id ? 'br-cascader__option-active' : ''}`}
                key={item.id} onClick={() => this.handleMenu(item)}>
                {item.name}
              </span>
            );
          })
        }
      </div>
    );
  }

  public componentDidMount() {
    this.initData(this.props);
    document.addEventListener('click', this.clickDocument, false);
  }

  public componentWillReceiveProps(nxtProps: ICascaderProps) {
    const { options, defaultValue = [] } = this.props;
    const { options: nxtOptions, defaultValue: nxtDefaultValue = [] } = nxtProps;
    if (options.length !== nxtOptions.length || defaultValue.length !== nxtDefaultValue.length) {
      this.initData(nxtProps);
    }
  }

  public render() {
    const { className, style, tabTitle = [], placeholder, value, ...domProps } = this.props;
    const { open, selectedMenu, showOptions, loading } = this.state;
    const { selectedMenuOptions } = this;
    const lastMenu = selectedMenuOptions.length && selectedMenuOptions[selectedMenuOptions.length - 1];
    const lastMenuEmpty = lastMenu && !lastMenu.length;
    const isTail = selectedMenu.length === tabTitle.length || lastMenuEmpty;
    const showDepthLevel = !loading && !!showOptions.length;
    return (
      <div
        {...domProps as IControledDOMProps}
        className={`br-cascader ${className}`}
        onClick={this.clickCascader}
        style={style}
      >
        <Dropdown open={open}
          popupClassName="br-cascader__popup-wrapper"
          controller={
            <div className={`br-cascader__value ${open ? 'br-cascader__value-open' : 'br-cascader__value-default'}`}
              onClick={this.inputClick}>
              <span>
                <span>{(value || selectedMenu).map((v, i) => v.name).join(' - ')}</span>
                {!!selectedMenu.length && !isTail && showDepthLevel && ' - '}
                {
                  !isTail && showDepthLevel && <span className="br-cascader__value-tips">
                    {!open && !selectedMenu.length ? placeholder : `请选择${tabTitle[selectedMenu.length]}`}
                  </span>
                }
              </span>
              <Icon type="down" className="br-cascader__value-icon" size={12} />
            </div>
          } >
          {() => (
            <section className="br-cascader__menu-wrapper">
              {this.renderMenuTab()}
              {this.renderMenuOptions()}
            </section>
          )}
        </Dropdown>
      </div>
    );
  }
}
